﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using Microsoft.Practices.Unity;
using Vit.Common;
using Vit.Common.Extensions;
using Vit.Web.Models;
using Vit.Web.Modules;
using Vit.Common.Providers;
using Vit.Web.Providers;
using Vit.Web.Helpers;

namespace Vit.Web
{
    public class PortalContext
    {
        public static PortalContext Current
        {
            get
            {
                var context =System.Web.HttpContext.Current;
                if (context != null)
                {
                    if (context.Items.Contains("CurrentWebContext"))
                        return context.Items["CurrentWebContext"] as PortalContext;
                    PortalContext webContext = new PortalContext();
                    context.Items.Add("CurrentWebContext", webContext);
                    return webContext;
                }

                return new PortalContext();
            }
        }

        private readonly ConcurrentDictionary<string, object> threadObjects = new ConcurrentDictionary<string, object>();

        public PortalContext()
        {
        }

        public void Refresh()
        {
            threadObjects.Clear();
        }

        private T GetThreadObject<T>(string name, Func<T> func)
        {
            if (func == null)
                return default(T);
            if (threadObjects.ContainsKey(name))
            {
                return (T)threadObjects[name];
            }

            T obj = func();
            if (obj != null)
            {
                return (T)threadObjects.GetOrAdd(name, obj);
            }
            return obj;
        }

        public Portal Portal
        {
            get
            {
                return GetThreadObject<Portal>("CurrentPortal", () =>
                    {
                        Portal portal = null;
                        try
                        {
                            portal = Unity.ResolveAny<IPortalProvider>().ForEach<IPortalProvider, Portal>(o => o.GetCurrentPortal());
                        }
                        catch { portal = null; }
                        if (portal != null && !string.IsNullOrEmpty(portal.ID))
                            return portal;

                        return null;
                    });
            }
        }

        public WebSite Site
        {
            get
            {
                return GetThreadObject<WebSite>("CurrentSite", () =>
                    {
                        WebSite site = null;
                        string domain = this.HttpContext.Request.Url.AbsoluteUri;
                        if (Portal != null && Portal.Sites.Count > 0)
                        {
                            foreach (var s in Portal.Sites)
                            {
                                if (Regex.IsMatch(domain, s.DomainPattern))
                                {
                                    site = s;
                                    break;
                                }
                            }
                        }
                        if (site != null && !string.IsNullOrEmpty(site.ID))
                            return site;
                        return null;
                    });
            }
        }

        public WebPage Page
        {
            get
            {
                return GetThreadObject<WebPage>("CurrentPage", () =>
                    {
                        if (Site != null && !string.IsNullOrEmpty(Site.ID))
                        {
                            string url = HttpContext.Request.Path;
                            IPortalProvider provider = Unity.Resolve<IPortalProvider>();
                            try
                            {
                                return provider.GetPageByUrl(Site, url);
                            }
                            catch
                            {
                            }
                        }
                        return null;
                    });
            }
        }

        public User User
        {
            get
            {
                User currentUser = GetThreadObject<User>("CurrentUser", () =>
                    {
                        User user = null;
                        if (HttpContext.User != null && HttpContext.User.Identity != null && !string.IsNullOrWhiteSpace(HttpContext.User.Identity.Name))
                        {
                            try
                            {
                                user = Unity.ResolveAny<IMembershipProvider>().ForEach<IMembershipProvider, User>(o => o.GetUser(HttpContext.User.Identity.Name));
                            }
                            catch { user = null; }
                            if (user != null && !string.IsNullOrEmpty(user.Account))
                                return user;
                        }
                        return null;
                    });

                if (currentUser == null)
                    currentUser = PortalHelper.CreateAnonymousUser();
                return currentUser;
            }
            set
            {
                threadObjects.AddOrUpdate("CurrentUser", value, (k, o) => o);
            }
        }

        public string Theme
        {
            get
            {
                return GetThreadObject<string>("CurrentTheme", () =>
                    {
                        if (AreaModule != null)
                        {
                            if (!string.IsNullOrEmpty(AreaModule.Theme))
                                return AreaModule.Theme;
                        }
                        return User.Profiles.Cast<Profile>().GetProfileValue("theme", "Default");
                    });
            }
        }

        public string Skin
        {
            get
            {
                return GetThreadObject<string>("CurrentSkin", () =>
                    {
                        if (AreaModule != null)
                        {
                            if (!string.IsNullOrEmpty(AreaModule.Skin))
                                return AreaModule.Skin;
                        }
                        return User.Profiles.Cast<Profile>().GetProfileValue("skin", "Default");
                    });
            }
        }

        public AreaModuleBase AreaModule
        {
            get
            {
                return GetThreadObject<AreaModuleBase>("CurrentAreaModule", () =>
                    {
                        AreaModuleBase areaModule = HttpContext.Items["areaModule"] as AreaModuleBase;
                        if (areaModule != null)
                            return areaModule;
                        var routeData = RouteTable.Routes.GetRouteData(HttpContext);
                        if (routeData != null && routeData.DataTokens["area"] != null)
                        {
                            areaModule = Unity.Resolve<IModule>(routeData.DataTokens["area"].ToString().ToLower()) as AreaModuleBase;
                            if (areaModule != null)
                            {
                                HttpContext.Items.Add("areaModule", areaModule);
                                return areaModule;
                            }
                        }

                        return null;
                    });
            }
        }

        public HttpContextBase HttpContext
        {
            get
            {
                return GetThreadObject<HttpContextBase>("HttpContext", () =>
                    {
                        return new HttpContextWrapper(System.Web.HttpContext.Current);
                    });
            }
        }

        public IUnityContainer Unity
        {
            get { return Vit.Common.Unity.Current; }
        }
    }
}
